package com.yzd.learnjava.concurrency;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.yzd.learnjava.util.Print;

public class ReaderWriterList<T> {
	private ArrayList<T> lockedList;
	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
	public ReaderWriterList(int size , T initialValue) {
		lockedList = new ArrayList<T>(Collections.nCopies(size, initialValue));
	}
	
	public T set(int index , T element) {
		Lock wLock = lock.writeLock();
		wLock.lock();
		try {
			return lockedList.set(index, element);
		} finally {
			wLock.unlock();
		}
	}
	
	public T get(int index) {
		Lock rLock = lock.readLock();
		rLock.lock();
		try {
			if(lock.getReadLockCount() > 1) {
				Print.print("readlock count : " + lock.getReadLockCount());
			}
			return lockedList.get(index);
		} finally {
			rLock.unlock();
		}
	}
	
	public static void main(String[] args) {
		new ReaderWriterListTest(30, 1);
	}
}

class ReaderWriterListTest {
	ExecutorService exec = Executors.newCachedThreadPool();
	private final static int SIZE = 100;
	private static Random random = new Random(47);
	private ReaderWriterList<Integer> list = new ReaderWriterList<Integer>(SIZE, 0);
	
	private class Writer implements Runnable{
		public void run() {
			try {
				for(int i = 0 ; i < 20; i++) {
					list.set(i, random.nextInt());
					TimeUnit.MILLISECONDS.sleep(100);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private class Reader implements Runnable{
		public void run() {
			try {
				while(!Thread.interrupted()) {
					for(int i = 0 ; i < SIZE; i++) {
						list.get(i);
						TimeUnit.MILLISECONDS.sleep(1);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public ReaderWriterListTest(int resders , int writers) {
		for(int i = 0 ; i < resders; i++) {
			exec.execute(new Reader());
		}
		for(int i = 0; i < writers; i++) {
			exec.execute(new Writer());
		}
	}
}


























